package easycloud.ecs.agent;

import java.io.File;
import java.lang.reflect.InvocationTargetException;

import javax.inject.Inject;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.reflect.ConstructorUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import easycloud.ecs.agent.batch.SendLogJob;
import easycloud.ecs.agent.config.AgentConfig;
import easycloud.ecs.agent.config.AgentConfigUtils;
import easycloud.ecs.common.domain.Provider;
import easycloud.ecs.common.domain.Provider.PROVIDER_TYPE;
import easycloud.ecs.common.domain.Sync;
import easycloud.ecs.common.domain.User;
import easycloud.ecs.common.exception.AgentException;
import easycloud.ecs.common.service.ProviderService;
import easycloud.ecs.common.service.UserService;
import easycloud.ecs.provider.api.IProvider;
import easycloud.ecs.provider.api.local.LocalProvider;

@Component
@Scope("singleton")
public class Agent {

	private static final Log logger = LogFactory.getLog(Agent.class);

	protected static AbstractApplicationContext context;

	public static void main(String[] args) throws Exception {
		Agent.context = new ClassPathXmlApplicationContext(new String[] {
				"classpath:agent-context.xml", "classpath:common-context.xml" });

		File configFile = new File(FileUtils.getUserDirectory(),
				"agent.config.json");
		if (!configFile.exists()) {
			configFile.createNewFile();
			AgentConfig defaultAgentConfig = new AgentConfig();
			defaultAgentConfig.setEmail("deliver.pub@gmail.com");
			defaultAgentConfig.setPassword("xiaolan");
			defaultAgentConfig.setProviderid(1);
			defaultAgentConfig.setConfigFile(configFile);
			AgentConfigUtils.saveAgentConifg(defaultAgentConfig);
		}

		AgentConfig agentConfig = AgentConfigUtils.getAgentConfig(configFile);
		Agent agent = (Agent) Agent.context.getBean("agent");
		agent.setAgentConfig(agentConfig);

		agent.signin();

		agent.initProvider();

		agent.showSyncInfo();

		Object lock = new Object();
		synchronized (lock) {
			lock.wait();
		}
	}

	private AgentConfig agentConfig;

	private Provider provider;

	private IProvider providerImpl;

	@Inject
	private UserService userService;

	@Inject
	private ProviderService providerService;

	private Agent() {
	}

	private boolean initProvider() throws AgentException {
		boolean result = false;
		if (provider.getProviderType().equals(PROVIDER_TYPE.CLOUD)) {
			try {
				@SuppressWarnings("rawtypes")
				Class providerClass = Class.forName(provider.getClassName());
				providerImpl = (IProvider) ConstructorUtils.invokeConstructor(
						providerClass, provider);
				result = providerImpl.ready();
			} catch (ClassNotFoundException e) {
				throw new AgentException("Init Provider Exception");
			} catch (NoSuchMethodException e) {
				throw new AgentException("Init Provider Exception");
			} catch (IllegalAccessException e) {
				throw new AgentException("Init Provider Exception");
			} catch (InvocationTargetException e) {
				throw new AgentException("Init Provider Exception");
			} catch (InstantiationException e) {
				throw new AgentException("Init Provider Exception");
			}
		} else if (provider.getProviderType().equals(PROVIDER_TYPE.LOCAL)) {
			providerImpl = new LocalProvider(provider);
		}

		SendLogJob sendLogJob = (SendLogJob) context.getBean("sendLogJob");
		providerImpl.setSendLogService(sendLogJob);
		return result;
	}

	public void setAgentConfig(AgentConfig config) {
		agentConfig = config;
	}

	private void showSyncInfo() {
		for (Sync sync : provider.getSyncs()) {
			System.out.println(sync.getFolder().getName() + " -> "
					+ sync.getPath());
		}
	}

	public Provider getProvider() {
		return this.provider;
	}

	public IProvider getProivderImpl() {
		return this.providerImpl;
	}

	private void signin() throws AgentException {
		Agent.logger.info("Agent signin begin");
		User user = userService.signin(agentConfig.getEmail(),
				agentConfig.getPassword());
		if (user != null) {
			provider = providerService.getProvider(agentConfig.getProviderid(),
					user);
		}
		if ((user == null) || (provider == null)) {
			throw new AgentException("Init Exception");
		}
		Agent.logger.info("Agent signin successed");
	}
}
